﻿/*
 * TokyoTyrant.NET (http://tokyotyrant.codeplex.com)
 * Pure .NET interface to Tokyo Tyrant
 * Copyright (C) 2009 Russell van der Walt (http://blog.ruski.co.za)

 * TokyoTyrant.NET is free software; you can redistribute it and/or modify it under the terms of
 * the Microsoft Public License (Ms-PL). TokyoTyrant.NET is distributed in the hope
 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the Microsoft Public
 * License for more details.
 * 
 * Tokyo Cabinet and Tokyo Tyrant is Copyright (C) 2006-2008 Mikio Hirabayashi 
 * http://tokyocabinet.sourceforge.net/
 * 
 */

using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using TokyoTyrant.NET;

namespace TokyoTyrantExample {

    class Program {

        static void Main(string[] args) {
            try {

                Console.Write("Enter the server name (localhost): ");
                string host  = Console.ReadLine();
                if (host == "") {
                    host = "localhost";
                }
                int port = 1978;

                using (var con = new TokyoTyrantConnection()) {
                    Console.WriteLine("host: " + host);
                    Console.WriteLine("port: " + port.ToString());
                    con.Connect(host, port);
                    var status = con.GetDatabaseStatus();
                    foreach (var key in status.Keys) {
                        Console.WriteLine(key + ": " + status[key]);
                    }
                    Console.WriteLine("");
                    OutputDatabaseSize(con);
                    Console.WriteLine("");
                    Console.WriteLine("WARNING: This will delete all data in the target database.");
                    Console.Write("Are you sure you wish to continue [y/N]?");
                    var chr = Console.ReadLine();
                    if (chr.ToUpper() == "Y") {

                        Console.WriteLine("\r\nClearing database...");
                        con.Vanish();
                        OutputDatabaseSize(con);
                        Console.WriteLine("");

                        if (status["type"] == "table") {
                            TableTest(con);
                        } else {
                            HashTest(con);
                        }
                        Console.WriteLine("\r\nSynchronizing database...");
                        con.Synchronize();

                        Console.WriteLine("\r\nOptimizing database...");
                        con.Optimize("");
                        OutputDatabaseSize(con);

                        Console.WriteLine("Press [ENTER] to terminate...");
                        Console.ReadLine();
                    }
                }


            } catch (Exception ex) {
                Console.WriteLine(ex.Message);
            }
        }

        public static void OutputDatabaseSize(TokyoTyrantConnection con) {
            var dbsize = con.GetDatabaseSize();
            var reccnt = con.GetRecordCount();
            Console.WriteLine("Database has " + reccnt + " records [" + dbsize.ToString() + " bytes]");
        }

        public static void TableTest(TokyoTyrantConnection con) {

            Console.WriteLine("\r\nRUNNING TABLE TESTS");
            Console.WriteLine("\r\nPopulating database...");
            var key = "";
            IDictionary<string, string> columns;
            var names = new string[] { "Mark", "Tom", "Harry", "Sally", "Sandra", "Paul", "Russell", "David", "Alex", "Michael", "Tina", "Zachary", "Bob", "Elise" };
            for (int i = 0; i < names.Length; i++) {
                key = string.Format("ID{0:00000}", i);
                columns = new Dictionary<string, string>();
                columns.Add("name", names[i]);
                columns.Add("age", Convert.ToString(10 + i));
                con.PutColumns(key, columns, true);
            }
            OutputDatabaseSize(con);


          

            Console.WriteLine("\r\nIterating records...");
            con.IteratorInitialize();
            Console.WriteLine("[ID]\t[Name]\t[Age]");
            while ((key = con.IteratorNext()) != null) {
                var column = con.GetColumns(new string[] { key })[key];
                Console.WriteLine(key + "\t" + column["name"] + "\t" + column["age"]);
            }

            Console.WriteLine("\r\nAdding an index...");
            con.SetIndex("name", TokyoTyrantConnection.IndexOption.ITLEXICAL);

            Console.WriteLine("\r\nQuerying keys...");
            var qkeys = con.QueryKeys(new TokyoQuery().StringStartsWith("name", "Sa"));
            var str = "";
            foreach (var k in qkeys) {
                str += k + ", ";
            }
            Console.WriteLine("Keys: " + str);

            Console.WriteLine("\r\nQuerying names...");
            var qrecords = con.QueryRecords(new TokyoQuery().StringStartsWith("name", "Sa"));
            Console.WriteLine("[ID]\t[Name]\t[Age]");
            foreach (var k in qrecords.Keys) {
                var column = qrecords[k];
                Console.WriteLine(k + "\t" + column["name"] + "\t" + column["age"]);
            }

            Console.WriteLine("\r\nQuerying ages...");
            qrecords = con.QueryRecords(new TokyoQuery().NumberGreaterThanOrEqual("age", 16).NumberLessThan("age", 20).OrderBy("age", TokyoQueryOrder.QONUMDESC).LimitTo(3, 0));
            Console.WriteLine("[ID]\t[Name]\t[Age]");
            foreach (var k in qrecords.Keys) {
                var column = qrecords[k];
                Console.WriteLine(k + "\t" + column["name"] + "\t" + column["age"]);
            }

            Console.WriteLine("\r\nDeleting with a query...");
            con.QueryDelete(new TokyoQuery().NumberGreaterThan("age", 20));
            OutputDatabaseSize(con);
            
            
            Console.WriteLine("\r\nDeleting first record...");
            con.Delete("ID00000");
            OutputDatabaseSize(con);
                        
            Console.WriteLine("\r\nDeleting 3 records...");
            con.DeleteMultiple(new string[] { "ID00000", "ID00001", "ID00002", "ID00003" });
            OutputDatabaseSize(con);
            
            Console.WriteLine("\r\nPrefix searching records...");
            var keys = con.GetMatchingKeys("ID", -1);
            Console.WriteLine("Retrieved " + keys.Length + " keys");
            Console.WriteLine("\r\nRetrieving batch records and checking size...");
            var records = con.GetColumns(keys);
            Console.WriteLine("[ID]\t[Name]\t[Age]\t[Size]");
            foreach (var k in records.Keys) {
                var column = records[k];
                var size = con.GetSize(k);
                Console.WriteLine(k + "\t" + column["name"] + "\t" + column["age"] + "\t" + size + " bytes");
            }





        }

        public static void HashTest(TokyoTyrantConnection con) {


            Console.WriteLine("\r\nRUNNING HASH TESTS");
            var key = "";

            Console.WriteLine("\r\nPopulating database with 3 items...");
            
            var names = new string[] { "Mark", "Tom", "Harry" };
            for (int i = 0; i < names.Length; i++) {
                key = string.Format("ID{0:00000}", i);
                if (i == 0) {
                    con.Put(key, names[i], true);
                } else
                    con.PutFast(key, names[i]);
            }
            OutputDatabaseSize(con);
            Console.WriteLine("\r\nPopulating database with 11 item in a batch...");
            names = new string[] { "Sally", "Sandra", "Paul", "Russell", "David", "Alex", "Michael", "Tina", "Zachary", "Bob", "Elise" };
            IDictionary<string, string> records = new Dictionary<string, string>();
            for (int i = 0; i < names.Length; i++) {
                key = string.Format("ID{0:00000}", i+3);
                records.Add(key, names[i]);
            }
            con.PutMultiple(records);
            OutputDatabaseSize(con);

            Console.WriteLine("\r\nIterating records...");
            con.IteratorInitialize();
            Console.WriteLine("[ID]\t[Name]");
            while ((key = con.IteratorNext()) != null) {
                var name = con.Get(key);
                Console.WriteLine(key + "\t" + name);
            }
            Console.WriteLine("\r\nDeleting first record...");
            con.Delete("ID00000");
            OutputDatabaseSize(con);

            Console.WriteLine("\r\nDeleting 2 records...");
            con.DeleteMultiple(new string[] { "ID00000", "ID00001", "ID00002" });
            OutputDatabaseSize(con);

            Console.WriteLine("\r\nConcatenating record...");
            con.Concatenate("ID00003", " Jones");
            Console.WriteLine("ID00003: " + con.Get("ID00003"));

            // haven't quite figured this one out yet
            Console.WriteLine("\r\nConcatenating record and shifting left...");
            con.ConcatenateShiftLeft("ID00003", "Kenny", 5);
            Console.WriteLine("ID00003: " + con.Get("ID00003"));
            

            Console.WriteLine("\r\nPrefix searching records...");
            var keys = con.GetMatchingKeys("ID", -1);
            Console.WriteLine("Retrieved " + keys.Length + " keys");
            Console.WriteLine("\r\nRetrieving batch records and checking size...");
            records = con.GetMultiple(keys);
            Console.WriteLine("[ID]\t[Name]\t[Size]");
            foreach (var k in records.Keys) {
                var size = con.GetSize(k);
                Console.WriteLine(k + "\t" + records[k] + "\t" + size + " bytes");
            }

            key = "NUM1";
            Console.WriteLine("\r\nInserting number...");
            Console.WriteLine(con.IncrementInteger(key, 1000000));
            Console.WriteLine(con.IncrementInteger(key, 2005000));
            Console.WriteLine(con.GetInteger(key));

        }

    }
}
